#include "BoundaryConditions.h"
#include <cmath>

// 构造函数
BoundaryConditions::BoundaryConditions(std::string type, std::vector<std::function<double(double, double)>> conditions)
    : type(type), conditions(conditions), _hasHole(false) {}

// 设置矩形域
void BoundaryConditions::setDomain(double xmin, double xmax, double ymin, double ymax) {
    this->xmin = xmin;
    this->xmax = xmax;
    this->ymin = ymin;
    this->ymax = ymax;
}

// 设置圆孔
void BoundaryConditions::setCircularHole(double centerX, double centerY, double radius) {
    this->centerX = centerX;
    this->centerY = centerY;
    this->radius = radius;
    this->_hasHole = true;
}

// 检查圆孔是否有效
bool BoundaryConditions::isValidHole(const Eigen::MatrixXd& grid) const {
    if (!_hasHole) return true;  // 如果没有圆孔，直接返回 true

    // 检查圆孔是否在矩形域内
    if (centerX - radius < xmin || centerX + radius > xmax ||
        centerY - radius < ymin || centerY + radius > ymax) {
        return false;
    }

    // 检查圆孔是否至少覆盖四个离散化点
    int count = 0;
    for (int i = 0; i < grid.rows(); ++i) {
        double x = grid(i, 0);
        double y = grid(i, 1);
        if ((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY) <= radius * radius) {
            count++;
            if (count >= 4) break;
        }
    }
    return (count >= 4);
}

// 获取边界条件类型
std::string BoundaryConditions::getType() const {
    return type;
}

// 获取某个边界条件值
double BoundaryConditions::getCondition(double x, double y, size_t index) const {
    if (index >= conditions.size()) {
        throw std::out_of_range("Index exceeds the number of available boundary conditions");
    }
    return conditions[index](x, y);
}

// 是否有圆孔
bool BoundaryConditions::hasHole() const {
    return _hasHole;
}

// 判断点是否在边界上
bool BoundaryConditions::isOnBoundary(double x, double y) const {
    // 矩形边界
    bool onRectBoundary = (x == xmin || x == xmax || y == ymin || y == ymax);

    // 圆孔边界
    bool onHoleBoundary = false;
    if (_hasHole) {
        double dist = (x - centerX) * (x - centerX) + (y - centerY) * (y - centerY);
        onHoleBoundary = (std::abs(dist - radius * radius) < 1e-6);
    }

    return (onRectBoundary || onHoleBoundary);
}
